﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CID.Execution.Support.Information;

namespace CID.Execution.Support.TemplateHandling
{
    public abstract class TemplateHandlerBase : ITemplateHandler
    {

        public void ExecuteTemplate(Information.TemplateInfo template, IEnumerable<Information.ParameterValueInfo> parameterValues, IEnumerable<Information.ParameterValueInfo> additionalParameterValues, IEnumerable<Information.ServerInfo> targetServers, StringBuilder detailsBuilder)
        {
            if (template.MultipleServersSupport) 
            {
                var effectiveParameterValues = parameterValues.Concat(additionalParameterValues).Concat(GetTargetServersAddressesParameter(targetServers));
                PrepareTemplate(template, effectiveParameterValues, detailsBuilder);
                try
                {
                    detailsBuilder.AppendFormat("Executing {0} template for {1} target servers", template.Name, targetServers.Count()).AppendLine();
                    ExecuteTemplate(template, effectiveParameterValues, detailsBuilder);
                    detailsBuilder.AppendFormat("Finisihed executing {0} template for {1} target servers", template.Name, targetServers.Count()).AppendLine();
                }
                finally
                {
                    ReleaseTemplate(template, detailsBuilder);
                }
            }
            else
            {
                foreach (var targetServer in targetServers)
                {
                    var effectiveParameterValues = parameterValues.Concat(additionalParameterValues).Concat(GetTargetServerAddressParameter(targetServer));
                    PrepareTemplate(template, effectiveParameterValues, detailsBuilder);
                    try
                    {
                        detailsBuilder.AppendFormat("Executing {0} template for target server {1}", template.Name, targetServer.Name).AppendLine();
                        ExecuteTemplate(template, effectiveParameterValues, detailsBuilder);
                        detailsBuilder.AppendFormat("Finisihed executing {0} template for target server {1}", template.Name, targetServer.Name).AppendLine();
                    }
                    finally
                    {
                        ReleaseTemplate(template, detailsBuilder);
                    }
                }
            }
        }

        #region Parameter methods
        private IEnumerable<ParameterValueInfo> GetTargetServerAddressParameter(ServerInfo targetServer)
        {
            return new ParameterValueInfo[] { 
                ParameterValueInfo.CreateAdditionalParameterValue(
                    ParameterValueInfo.ReservedParameterNames.TargetServerAddress, 
                    targetServer.Address
                ) 
            };
        }

        private IEnumerable<ParameterValueInfo> GetTargetServersAddressesParameter(IEnumerable<ServerInfo> targetServers)
        {
            return new ParameterValueInfo[] { 
                ParameterValueInfo.CreateAdditionalParameterValue(
                    ParameterValueInfo.ReservedParameterNames.TargetServersAddresses, 
                    String.Join("; ", targetServers.Select(x=>x.Address).ToArray())
                ) 
            };
        }
        #endregion

        protected abstract void PrepareTemplate(TemplateInfo template, IEnumerable<ParameterValueInfo> parameterValues, StringBuilder detailsBuilder);

        protected abstract void ExecuteTemplate(TemplateInfo template, IEnumerable<ParameterValueInfo> parameterValues, StringBuilder detailsBuilder);

        protected abstract void ReleaseTemplate(TemplateInfo template, StringBuilder detailsBuilder);
    }
}
